﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace Project3
{
    public class ObjectField
    {
        public class Asteroid : Collidable
        {
            public Vector3 position;
            public override Vector3 Position { get { return position; } set { position = value; } }

            public int model;
            public Vector3 velocity;
            public float size;

            public Vector3 p0, p1, p2, p3;
            public Vector3 v0, v1, v2, v3;
            public int time;
            public bool flag = true;
        }


        const float scalefactor = 4;
        float radius = 60;
        int asteroidcount = 25;
        PhibesGame game;

        private LinkedList<Asteroid> asteroids = new LinkedList<Asteroid>();

        public LinkedList<Asteroid> Asteroids { get { return asteroids; } }

        private Model[] models = new Model[3];
        private Random random = new Random();

        public ObjectField(PhibesGame game)
        {
            this.game = game;
            radius *= scalefactor;
        }

        private Vector3 RandomVector(float min, float max)
        {
            return new Vector3((float)(min + (random.NextDouble() * (max - min))),
                (float)(min + ((random.NextDouble() / 2 + 0.25) * (max - min))),
                (float)(min + (random.NextDouble() * (max - min))));
        }

        public void LoadContent(ContentManager content)
        {
            models[0] = content.Load<Model>("Asteroid1");
            models[1] = content.Load<Model>("Asteroid2");
            models[2] = content.Load<Model>("Asteroid3");
        }

        public void Update(GameTime gameTime)
        {
            //Move this object along a curve
            foreach (Asteroid curr in asteroids)
            {
                Vector3 tmp;
                float count = 100;
                if (curr.flag)
                {
                    curr.time += 1;
                    tmp = GetPoint((curr.time / count), curr.p0, curr.p1, curr.p2, curr.p3);
                    if (curr.time > 100)
                    {
                        curr.flag = false;
                        curr.time = 0;
                    }
                }
                else
                {
                    tmp = GetPoint((curr.time / count), curr.p3, curr.v1, curr.v2, curr.p0);
                    curr.time += 1;
                    if (curr.time > 100)
                    {
                        curr.flag = true;
                        curr.time = 0;
                    }
                }

                curr.position.X = tmp.X;
                curr.position.Y = tmp.Y;
                curr.position.Z = tmp.Z;
            }
        }

        public void Initialize()
        {
            while(asteroids.Count < asteroidcount)
            {
                Asteroid asteroid = new Asteroid();
                asteroid.model = random.Next(3);
                asteroid.position = RandomVector(-3000, 3000);
                asteroid.velocity = RandomVector(-300, 300);
                asteroid.size = 10;

                asteroid.p0 = RandomVector(-2000, 2000);
                asteroid.p1 = RandomVector(-2000, 2000);
                asteroid.p2 = RandomVector(-2000, 2000);
                asteroid.p3 = RandomVector(-2000, 2000);

                asteroid.v0 = RandomVector(-500, 500);
                asteroid.v1 = RandomVector(-500, 500);
                asteroid.v2 = RandomVector(-500, 500);
                asteroid.v3 = RandomVector(-500, 500);

                asteroid.AddCollisionPoint(0, 0, radius);

                if (asteroid.position.Length() < 1000)
                    continue;

                asteroids.AddLast(asteroid);
            }

        }
        public void Draw(GraphicsDeviceManager graphics, GameTime gameTime)
        {
            for (LinkedListNode<Asteroid> node = asteroids.First; node != null; )
            {
                LinkedListNode<Asteroid> next = node.Next;
                Asteroid curr = node.Value;

                DrawModel(graphics, models[curr.model], Matrix.CreateScale(scalefactor) * Matrix.CreateTranslation(curr.position));
                node = next;
            }
        }

        private void DrawModel(GraphicsDeviceManager graphics, Model model, Matrix world)
        {
            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);

            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.World = transforms[mesh.ParentBone.Index] * world;
                    effect.View = game.Camera.View;
                    effect.Projection = game.Camera.Projection;
                }
                mesh.Draw();
            }
        }

        private Vector3 GetPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
        {
            float cx = 3 * (p1.X - p0.X);
            float cy = 3 * (p1.Y - p0.Y);
            float cz = 3 * (p1.Z - p0.Z);

            float bx = 3 * (p2.X - p1.X) - cx;
            float by = 3 * (p2.Y - p1.Y) - cy;
            float bz = 3 * (p2.Z - p1.Z) - cz;

            float ax = p3.X - p0.X - cx - bx;
            float ay = p3.Y - p0.Y - cy - by;
            float az = p3.Z - p0.Z - cz - bz;

            float Cube = t * t * t;
            float Square = t * t;

            float resX = (ax * Cube) + (bx * Square) + (cx * t) + p0.X;
            float resY = (ay * Cube) + (by * Square) + (cy * t) + p0.Y;
            float resZ = (az * Cube) + (bz * Square) + (cz * t) + p0.Z;

            return new Vector3(resX, resY, resZ);
        }

    }
}
